package com.qqt.csr.order.service;

import cn.hutool.core.thread.ThreadUtil;
import com.google.common.collect.Lists;
import com.qqt.csr.common.utils.CacheKeyUtil;
import com.qqt.csr.common.utils.RedissonLockUtil;
import com.qqt.csr.common.utils.SnowflakeUtil;
import com.qqt.csr.order.entity.WorkOrder;
import com.qqt.csr.order.entity.WorkOrderEvent;
import com.qqt.csr.order.enums.WorkOrderStatusEnum;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WorkOrderElapsedTimeService implements InitializingBean {
    private static final String LOG_TID = "ctid";
    private final ScheduledThreadPoolExecutor executor = ThreadUtil.createScheduledExecutor(1);
    private volatile boolean isShutdown = false;

    @Autowired
    private RedissonLockUtil redissonLockUtil;
    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private WorkOrderEventService workOrderEventService;

    @Override
    public void afterPropertiesSet() throws Exception {
        ThreadUtil.schedule(executor,
                () -> {
                    try {
                        MDC.put(LOG_TID, SnowflakeUtil.nextIdStr());
                        redissonLockUtil.distributedLock(this::calculate, CacheKeyUtil.Order.CALCULATE_ELAPSED_TIME_LOCK);
                    } catch (Throwable e) {
                        log.error("处理中的工单已耗时统计任务执行异常", e);
                    } finally {
                        MDC.clear();
                    }
                },
                30,
                30,
                TimeUnit.SECONDS,
                false
        );
    }

    @PreDestroy
    public void destroy() {
        isShutdown = true;
        executor.shutdown();
        log.info("处理中的工单已耗时统计任务已关闭");
    }

    private void calculate() {
        Long lastOrderId = 0L;
        do {
            List<WorkOrder> orderList = workOrderService.getListForCalculatingElapsedTime(lastOrderId, 100);
            if (CollectionUtils.isEmpty(orderList)) {
                return;
            }

            List<Long> orderIdList = orderList.stream().map(WorkOrder::getId).collect(Collectors.toList());
            Map<Long, List<WorkOrderEvent>> orderEventMap = workOrderEventService.getMapBy(orderIdList);

            List<WorkOrder> updateElapsedTimeOrderList = Lists.newArrayList();

            for (WorkOrder order : orderList) {
                List<WorkOrderEvent> workOrderEvents = orderEventMap.get(order.getId());
                if (CollectionUtils.isEmpty(workOrderEvents)) {
                    continue;
                }

                workOrderEvents.sort(Comparator.comparing(WorkOrderEvent::getCreateTime));
                //计算耗时，其他->处理中，处理中->处理中，处理中->其他，处理中
                Long elapsedTimeSec = 0L;
                Date lastProcessStartTime = null;
                for (WorkOrderEvent workOrderEvent : workOrderEvents) {
                    if (workOrderEvent.getTo().equals(WorkOrderStatusEnum.TO_PROCESS.getStatus())) {
                        if (lastProcessStartTime != null) {
                            elapsedTimeSec = elapsedTimeSec + ((System.currentTimeMillis() - lastProcessStartTime.getTime()) / 1000);
                        }
                        lastProcessStartTime = workOrderEvent.getCreateTime();
                    } else if (lastProcessStartTime != null) {
                        elapsedTimeSec = elapsedTimeSec + ((System.currentTimeMillis() - lastProcessStartTime.getTime()) / 1000);
                        lastProcessStartTime = null;
                    }
                }

                if (lastProcessStartTime != null) {
                    elapsedTimeSec = elapsedTimeSec + ((System.currentTimeMillis() - lastProcessStartTime.getTime()) / 1000);
                }

                if (elapsedTimeSec.compareTo(order.getElapsedTime()) > 0) {
                    updateElapsedTimeOrderList.add(WorkOrder.builder().id(order.getId()).elapsedTime(elapsedTimeSec).build());
                }
            }

            if (CollectionUtils.isNotEmpty(updateElapsedTimeOrderList)) {
                updateElapsedTimeOrderList.sort(Comparator.comparing(WorkOrder::getId));
                Lists.partition(updateElapsedTimeOrderList, 100).forEach(workOrderService::updateBatchById);
            }

            lastOrderId = orderList.get(orderList.size() - 1).getId();
        } while (!isShutdown);
    }

}
